package com.algo.rpc.client;

import com.algo.rpc.common.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;

import java.util.Date;
import java.util.concurrent.ConcurrentHashMap;

public class RpcNettyClientHandler extends ChannelInboundHandlerAdapter {
    // 每个50ms获取一次请求结果
    private static final int GET_RESPONSE_INTERVAL = 50;

    // 内部持有请求开始时间
    private RpcRequestTimeHolder requestTimeHolder;

    // 默认请求的超时时间，默认毫秒
    private long timeout;

    private ConcurrentHashMap<String, RpcResponse> responseMap = new ConcurrentHashMap<String, RpcResponse>();

    public RpcNettyClientHandler(RpcRequestTimeHolder requestTimeHolder, long timeout) {
        this.requestTimeHolder = requestTimeHolder;
        this.timeout = timeout;
    }

    @Override
    public void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        RpcResponse response = (RpcResponse) msg;
        if (hasBeenTimeout(response.getRequestId())) {
            requestTimeHolder.remove(response.getRequestId());
            return;
        }
        responseMap.put(response.getRequestId(), response);
    }

    /**
     * 获取请求结果
     *
     * @param requestId
     * @return
     */
    public RpcResponse getResposne(String requestId) throws Throwable {
        while (!hasBeenTimeout(requestId)) {
            RpcResponse response = responseMap.get(requestId);
            if (response != null) {
                if (!response.isSuccess()) {
                    throw response.getError();
                }
                return response;
            }
            try {
                Thread.sleep(GET_RESPONSE_INTERVAL);
            } catch (Exception e){
                //
            }
        }
        throw new RequestTimeoutException("rpc client request has been timeout, requestId is " + requestId);
    }

    /**
     * 判断请求是否超时
     *
     * @param requestId
     */
    private boolean hasBeenTimeout(String requestId) {
        long curTime = System.currentTimeMillis();
        Long requestStartTime = requestTimeHolder.get(requestId);
        if (requestStartTime == null) {
            return true;
        }
        return curTime - requestStartTime > timeout;
    }

}



